<?php
namespace app\wx\controller;

use think\Cache;
use think\Controller;
use think\Request;

class Wx extends Controller
{

    public $request;
    public $access_token;
    public $jsapi_ticket;
    public $tokentimeout = 600;
    public function __construct()
    {
        parent::__construct();
        $this->request = $request = Request::instance();
        $this->update_access_token();
    }

    public function update_access_token()
    {
        $token = Cache::get("access_token");
        if ((empty($token) || $token['timeout'] < TIME) && $this->config['appid'] != '') {
            $use = Cache::inc("access_token_use");
            if ($use != '1') {
                sleep(5); //暂停5秒
                Cache::del("access_token_use");
                $this->redirect('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PATH_INFO'] . '?' . $_SERVER['QUERY_STRING']); //重定向
            }
            $result             = action('Wx_communication/get_access_token'); //$this->communication->get_access_token();
            $this->access_token = $result['access_token'];
            Cache::set('access_token', array('access_token' => $this->access_token, 'timeout' => TIME + $this->tokentimeout), $this->tokentimeout * 24);
            $result = action('Wx_communication/get_jsapi_ticket', $this->access_token);
            //$this->communication->get_jsapi_ticket($this->access_token);
            $this->jsapi_ticket = $result['ticket'];
            Cache::set('jsapi_ticket', $this->jsapi_ticket, $this->tokentimeout * 24);
            Cache::del("access_token_use");
        } else {
            $this->access_token = $token['access_token'];
            $this->jsapi_ticket = Cache::set("jsapi_ticket");
            Cache::del("access_token_use");
        }
    }

    public function jssignature($url)
    {
        $signature = array(
            'timestamp'    => TIME,
            'noncestr'     => uniqid(),
            'jsapi_ticket' => $this->jsapi_ticket,
            'url'          => empty($url) ? 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] : $url,
        );
        $po = strrpos($signature['url'], "#");
        if ($po !== false) {
            $signature['url'] = substr($signature['url'], 0, $po);
        }
        //$signature['url']=trim($signature['url'],'?');
        ksort($signature);
        $str = '';
        foreach ($signature as $k => $v) {
            $str .= $k . '=' . $v . '&';
        }
        $str                    = trim($str, '&');
        $signature['signature'] = sha1($str);
        return $signature;
    }

    public function http_request($url, $post = '', $extra = array(), $timeout = null, $check = true)
    {
        $timeout = $timeout == null ? $this->timeout : $timeout;
        $urlset  = parse_url($url);
        if (empty($urlset['path'])) {
            $urlset['path'] = '/';
        }
        if (!empty($urlset['query'])) {
            $urlset['query'] = "?{$urlset['query']}";
        }
        if (empty($urlset['port'])) {
            $urlset['port'] = $urlset['scheme'] == 'https' ? '443' : '80';
        }

        if (!function_exists('curl_init') && !function_exists('curl_exec')) {
            return $this->error_handle('请开启您PHP环境的curl', 500);
        }

        $ch = curl_init();

        if (!empty($extra['ip'])) {
            $extra['Host']  = $urlset['host'];
            $urlset['host'] = $extra['ip'];
            unset($extra['ip']);
        }
        @curl_setopt($ch, CURLOPT_URL, $urlset['scheme'] . '://' . $urlset['host'] . ($urlset['port'] == '80' ? '' : ':' . $urlset['port']) . $urlset['path'] . $urlset['query']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        @curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        if ($post) {
            if (is_array($post)) {
                $filepost = false;
                foreach ($post as $name => $value) {
                    if ((is_string($value) && substr($value, 0, 1) == '@') || (class_exists('CURLFile') && $value instanceof CURLFile)) {
                        $filepost = true;
                        break;
                    }
                }
                if (!$filepost) {
                    $post = http_build_query($post);
                }
            }
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        }

        /*
        if (!empty($GLOBALS['_W']['config']['setting']['proxy'])) {
        $urls = parse_url($GLOBALS['_W']['config']['setting']['proxy']['host']);
        if (!empty($urls['host'])) {
        curl_setopt($ch, CURLOPT_PROXY, "{$urls['host']}:{$urls['port']}");
        $proxytype = 'CURLPROXY_' . strtoupper($urls['scheme']);
        if (!empty($urls['scheme']) && defined($proxytype)) {
        curl_setopt($ch, CURLOPT_PROXYTYPE, constant($proxytype));
        } else {
        curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
        curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
        }
        if (!empty($GLOBALS['_W']['config']['setting']['proxy']['auth'])) {
        curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['_W']['config']['setting']['proxy']['auth']);
        }
        }
        }
         */

        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSLVERSION, 1);
        if (defined('CURL_SSLVERSION_TLSv1')) {
            curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
        }
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1');
        if (!empty($extra) && is_array($extra)) {
            $headers = array();
            foreach ($extra as $opt => $value) {
                if (strexists($opt, 'CURLOPT_')) {
                    curl_setopt($ch, constant($opt), $value);
                } elseif (is_numeric($opt)) {
                    curl_setopt($ch, $opt, $value);
                } else {
                    $headers[] = "{$opt}: {$value}";
                }
            }
            if (!empty($headers)) {
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            }
        }
        $data   = curl_exec($ch);
        $status = curl_getinfo($ch);
        $errno  = curl_errno($ch);
        $error  = curl_error($ch);
        curl_close($ch);
        if ($errno || empty($data)) {
            return $this->error_handle($error);
        } else {

            $response = $this->http_response_parse($data);
            if (!$check) {
                return $response;
            }
            $result = @json_decode($response['content'], true);
            if (empty($result)) {
                return $this->error_handle("接口调用失败, 元数据: {$response['meta']}");
            } elseif (!empty($result['errcode'])) {
                return $this->error_handle("访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']}");
            }
            if ($this->is_error($result)) {
                return $this->error_handle($result['message']);
            }
            return $result;
        }
    }

    public function http_response_parse($data, $chunked = false)
    {
        $rlt        = array();
        $headermeta = explode('HTTP/', $data);
        if (count($headermeta) > 2) {
            $data = 'HTTP/' . array_pop($headermeta);
        }
        $pos       = strpos($data, "\r\n\r\n");
        $split1[0] = substr($data, 0, $pos);
        $split1[1] = substr($data, $pos + 4, strlen($data));

        $split2 = explode("\r\n", $split1[0], 2);
        preg_match('/^(\S+) (\S+) (\S+)$/', $split2[0], $matches);
        $rlt['code']         = $matches[2];
        $rlt['status']       = $matches[3];
        $rlt['responseline'] = $split2[0];
        $header              = explode("\r\n", $split2[1]);
        $isgzip              = false;
        $ischunk             = false;
        foreach ($header as $v) {
            $pos   = strpos($v, ':');
            $key   = substr($v, 0, $pos);
            $value = trim(substr($v, $pos + 1));
            if (@is_array($rlt['headers'][$key])) {
                $rlt['headers'][$key][] = $value;
            } elseif (!empty($rlt['headers'][$key])) {
                $temp = $rlt['headers'][$key];
                unset($rlt['headers'][$key]);
                $rlt['headers'][$key][] = $temp;
                $rlt['headers'][$key][] = $value;
            } else {
                $rlt['headers'][$key] = $value;
            }
            if (!$isgzip && strtolower($key) == 'content-encoding' && strtolower($value) == 'gzip') {
                $isgzip = true;
            }
            if (!$ischunk && strtolower($key) == 'transfer-encoding' && strtolower($value) == 'chunked') {
                $ischunk = true;
            }
        }
        if ($chunked && $ischunk) {
            $rlt['content'] = $this->http_response_parse_unchunk($split1[1]);
        } else {
            $rlt['content'] = $split1[1];
        }
        if ($isgzip && function_exists('gzdecode')) {
            $rlt['content'] = gzdecode($rlt['content']);
        }

        $rlt['meta'] = $data;
        if ($rlt['code'] == '100') {
            return $this->http_response_parse($rlt['content']);
        }
        return $rlt;
    }

    public function http_response_parse_unchunk($str = null)
    {
        if (!is_string($str) or strlen($str) < 1) {
            return false;
        }
        $eol = "\r\n";
        $add = strlen($eol);
        $tmp = $str;
        $str = '';
        do {
            $tmp = ltrim($tmp);
            $pos = strpos($tmp, $eol);
            if ($pos === false) {
                return false;
            }
            $len = hexdec(substr($tmp, 0, $pos));
            if (!is_numeric($len) or $len < 0) {
                return false;
            }
            $str .= substr($tmp, ($pos + $add), $len);
            $tmp   = substr($tmp, ($len + $pos + $add));
            $check = trim($tmp);
        } while (!empty($check));
        unset($tmp);
        return $str;
    }

    public function http_get($url)
    {
        return $this->http_request($url);
    }

    public function http_post($url, $data)
    {
        $headers = array('Content-Type' => 'application/x-www-form-urlencoded');
        return $this->http_request($url, $data, $headers);
    }

    public function is_error($data)
    {
        if (empty($data) || !is_array($data) || !array_key_exists('errno', $data)) {
            return false;
        } else {
            return true;
        }
    }
    public function set_error_show($is)
    {
        $this->iserrorshow = $is === false ? false : true;
    }

    public function set_timeout($time)
    {
        $this->timeout = $time;
    }

    public function error_handle($err, $err_code = 500)
    {
        $this->error = $err;
        if ($this->iserrorshow) {
            show_error($err, $err_code);
        }
        return false;
    }

    public function httprequest($url, $post = '', $extra = array(), $timeout = null, $check = true)
    {
        $timeout = $timeout == null ? $this->timeout : $timeout;
        $urlset  = parse_url($url);
        if (empty($urlset['path'])) {
            $urlset['path'] = '/';
        }
        if (!empty($urlset['query'])) {
            $urlset['query'] = "?{$urlset['query']}";
        }
        if (empty($urlset['port'])) {
            $urlset['port'] = $urlset['scheme'] == 'https' ? '443' : '80';
        }

        if (!function_exists('curl_init') && !function_exists('curl_exec')) {
            return $this->error_handle('请开启您PHP环境的curl', 500);
        }

        $ch = curl_init();

        if (!empty($extra['ip'])) {
            $extra['Host']  = $urlset['host'];
            $urlset['host'] = $extra['ip'];
            unset($extra['ip']);
        }
        @curl_setopt($ch, CURLOPT_URL, $urlset['scheme'] . '://' . $urlset['host'] . ($urlset['port'] == '80' ? '' : ':' . $urlset['port']) . $urlset['path'] . $urlset['query']);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        @curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
        if ($post) {
            if (is_array($post)) {
                $filepost = false;
                foreach ($post as $name => $value) {
                    if ((is_string($value) && substr($value, 0, 1) == '@') || (class_exists('CURLFile') && $value instanceof CURLFile)) {
                        $filepost = true;
                        break;
                    }
                }
                if (!$filepost) {
                    $post = http_build_query($post);
                }
            }
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        }

        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSLVERSION, 1);
        if (defined('CURL_SSLVERSION_TLSv1')) {
            curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
        }
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:9.0.1) Gecko/20100101 Firefox/9.0.1');
        if (!empty($extra) && is_array($extra)) {
            $headers = array();
            foreach ($extra as $opt => $value) {
                if (strexists($opt, 'CURLOPT_')) {
                    curl_setopt($ch, constant($opt), $value);
                } elseif (is_numeric($opt)) {
                    curl_setopt($ch, $opt, $value);
                } else {
                    $headers[] = "{$opt}: {$value}";
                }
            }
            if (!empty($headers)) {
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            }
        }
        $data   = curl_exec($ch);
        $status = curl_getinfo($ch);
        $errno  = curl_errno($ch);
        $error  = curl_error($ch);
        curl_close($ch);
        if ($errno || empty($data)) {
            return $this->error_handle($error);
        } else {

            $response = $this->http_response_parse($data);
            if (!$check) {
                return $response;
            }
            $result = @json_decode($response['content'], true);
            if (empty($result)) {
                return $this->error_handle("接口调用失败, 元数据: {$response['meta']}");
            } elseif (!empty($result['errcode'])) {
                return $this->error_handle("访问微信接口错误, 错误代码: {$result['errcode']}, 错误信息: {$result['errmsg']}");
            }
            if ($this->is_error($result)) {
                return $this->error_handle($result['message']);
            }
            return $result;
        }
    }

}
